package org.dromara.assets.config;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.assets.domain.AssetsTradePlan;
import org.dromara.assets.mapper.AssetsTradePlanMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.action.Action;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.config.builders.StateMachineConfigBuilder;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.guard.Guard;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.EnumSet;

@Slf4j
@Configuration
@EnableStateMachine(name = "tradePlanStatusMachine")
@EnableScheduling
public class TradeStateMachineConfig extends StateMachineConfigurerAdapter<TradePlanStatusEnum, TradePlanStatusEventEnum> {

    @Autowired
    private AssetsTradePlanMapper assetsTradePlanMapper;


    @Override
    public void configure(StateMachineStateConfigurer<TradePlanStatusEnum, TradePlanStatusEventEnum> states) throws Exception {
        states.withStates()
                .initial(TradePlanStatusEnum.STATE_1)
                .states(EnumSet.allOf(TradePlanStatusEnum.class))
                .end(TradePlanStatusEnum.STATE_20);
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<TradePlanStatusEnum, TradePlanStatusEventEnum> transitions) throws Exception {
        log.info("begin to config state machine transitions");
        transitions
                // STATE_1 -> STATE_2: 币价判断
                .withExternal().source(TradePlanStatusEnum.STATE_1).target(TradePlanStatusEnum.STATE_2)
                .event(TradePlanStatusEventEnum.CHECK_PRICE).guard(priceMetGuard())
                .action(updateStateAction())

                // STATE_2 -> STATE_21: 赎回
                .and().withExternal().source(TradePlanStatusEnum.STATE_2).target(TradePlanStatusEnum.STATE_21)
                .event(TradePlanStatusEventEnum.STARTED).guard(redeemNeededGuard())
                .action(redeemAction()).action(updateStateAction())

                // STATE_21 -> STATE_22: 币币交换（赎回后）
                .and().withExternal().source(TradePlanStatusEnum.STATE_21).target(TradePlanStatusEnum.STATE_22)
                .event(TradePlanStatusEventEnum.REDEEM).guard(swapNeededGuard())
                .action(swapAction()).action(updateStateAction())

                // STATE_2 -> STATE_22: 直接币币交换（无需赎回）
                .and().withExternal().source(TradePlanStatusEnum.STATE_2).target(TradePlanStatusEnum.STATE_22)
                .event(TradePlanStatusEventEnum.STARTED).guard(swapNeededAndNoRedeemGuard())
                .action(swapAction()).action(updateStateAction())

                // STATE_22 -> STATE_3: 准备完成
                .and().withExternal().source(TradePlanStatusEnum.STATE_22).target(TradePlanStatusEnum.STATE_3)
                .event(TradePlanStatusEventEnum.PREPARE_COMPLETE)
                .action(updateStateAction())

                // STATE_3 -> STATE_4: 下单
                .and().withExternal().source(TradePlanStatusEnum.STATE_3).target(TradePlanStatusEnum.STATE_4)
                .event(TradePlanStatusEventEnum.PLACE_ORDER)
                .action(placeOrderAction()).action(updateStateAction())

                // STATE_4 -> STATE_5: 未成交且币价到位
                .and().withExternal().source(TradePlanStatusEnum.STATE_4).target(TradePlanStatusEnum.STATE_5)
                .event(TradePlanStatusEventEnum.CHECK_TRANSACTION).guard(notTransactedAndPriceMetGuard())
                .action(updateStateAction())

                // STATE_4 -> STATE_6: 已成交
                .and().withExternal().source(TradePlanStatusEnum.STATE_4).target(TradePlanStatusEnum.STATE_6)
                .event(TradePlanStatusEventEnum.CHECK_TRANSACTION).guard(transactedGuard())
                .action(updateStateAction())

                // STATE_5 -> STATE_20: 告警
                .and().withExternal().source(TradePlanStatusEnum.STATE_5).target(TradePlanStatusEnum.STATE_20)
                .event(TradePlanStatusEventEnum.ALERT)
                .action(sendAlertEmailAction()).action(updateStateAction())

                // STATE_6 -> STATE_20: 通知
                .and().withExternal().source(TradePlanStatusEnum.STATE_6).target(TradePlanStatusEnum.STATE_20)
                .event(TradePlanStatusEventEnum.NOTIFY)
                .action(sendNotifyEmailAction()).action(updateStateAction());
    }

    // 守卫（Guard）
    @Bean
    public Guard<TradePlanStatusEnum, TradePlanStatusEventEnum> priceMetGuard() {
        return context -> {
            log.info("begin priceMetGuard");
            AssetsTradePlan plan = getPlanFromContext(context);
            BigDecimal current = plan.getCurrentPrice() != null ? plan.getCurrentPrice() : getCurrentPrice(plan.getSymbol());
            plan.setCurrentPrice(current);
            //assetsTradePlanMapper.save(plan);
            return current != null && current.compareTo(plan.getTriggerPrice()) < 0;
        };
    }

    @Bean
    public Guard<TradePlanStatusEnum, TradePlanStatusEventEnum> redeemNeededGuard() {
        return context -> getPlanFromContext(context).getIsRedeemNeeded();
    }

    @Bean
    public Guard<TradePlanStatusEnum, TradePlanStatusEventEnum> swapNeededGuard() {
        return context -> getPlanFromContext(context).getIsSwapNeeded();
    }

    @Bean
    public Guard<TradePlanStatusEnum, TradePlanStatusEventEnum> swapNeededAndNoRedeemGuard() {
        return context -> swapNeededGuard().evaluate(context) && !redeemNeededGuard().evaluate(context);
    }

    @Bean
    public Guard<TradePlanStatusEnum, TradePlanStatusEventEnum> notTransactedAndPriceMetGuard() {
        return context -> {
            AssetsTradePlan plan = getPlanFromContext(context);
            boolean notTransacted = "PENDING".equals(plan.getTransactionStatus());
            boolean priceMet = isPriceAtPosition(plan);
            if (priceMet) {
                plan.setCurrentPrice(getCurrentPrice(plan.getSymbol()));
                //repository.save(plan);
            }
            return notTransacted && priceMet;
        };
    }

    @Bean
    public Guard<TradePlanStatusEnum, TradePlanStatusEventEnum> transactedGuard() {
        return context -> "COMPLETED".equals(getPlanFromContext(context).getTransactionStatus());
    }

    // 动作（Action）
    @Bean
    public Action<TradePlanStatusEnum, TradePlanStatusEventEnum> redeemAction() {
        return context -> {
            AssetsTradePlan plan = getPlanFromContext(context);
            // 模拟赎回：调用API赎回 redeemSymbol
            plan.setRemarks(plan.getRemarks() + "; Redeemed: " + plan.getRedeemSymbol());
        };
    }

    @Bean
    public Action<TradePlanStatusEnum, TradePlanStatusEventEnum> swapAction() {
        return context -> {
            log.info("begin swapAction");
            AssetsTradePlan plan = getPlanFromContext(context);
            // 模拟币币交换：挂单 swapSymbol
            plan.setRemarks(plan.getRemarks() + "; Swapped: " + plan.getSwapSymbol());
        };
    }

    @Bean
    public Action<TradePlanStatusEnum, TradePlanStatusEventEnum> placeOrderAction() {
        return context -> {
            log.info("begin placeOrderAction");
            AssetsTradePlan plan = getPlanFromContext(context);
            // 模拟下单：使用 orderPrice 和 tradeType
            plan.setOrderId("ORDER-" + System.currentTimeMillis());
            plan.setTransactionStatus("PENDING");
            plan.setRemarks(plan.getRemarks() + "; Placed order at " + plan.getOrderPrice());
        };
    }

    @Bean
    public Action<TradePlanStatusEnum, TradePlanStatusEventEnum> sendAlertEmailAction() {
        return context -> {
            log.info("begin sendAlertEmailAction");
            AssetsTradePlan plan = getPlanFromContext(context);
            // 模拟发送告警邮件
            plan.setAlertSentAt(LocalDateTime.now());
            plan.setRemarks(plan.getRemarks() + "; Alert email sent");
        };
    }

    @Bean
    public Action<TradePlanStatusEnum, TradePlanStatusEventEnum> sendNotifyEmailAction() {
        return context -> {
            log.info("begin sendNotifyEmailAction");
            AssetsTradePlan plan = getPlanFromContext(context);
            // 模拟发送通知邮件
            plan.setNotifySentAt(LocalDateTime.now());
            plan.setRemarks(plan.getRemarks() + "; Notify email sent");
        };
    }

    @Bean
    public Action<TradePlanStatusEnum, TradePlanStatusEventEnum> updateStateAction() {
        return context -> {
            log.info("begin updateStateAction");
            AssetsTradePlan plan = getPlanFromContext(context);
            plan.setUpdatedAt(LocalDateTime.now());
            assetsTradePlanMapper.update(null, new LambdaUpdateWrapper<AssetsTradePlan>()
                    .set(AssetsTradePlan::getUpdatedAt, LocalDateTime.now())
                    .eq(AssetsTradePlan::getId, plan.getId()));
        };
    }

    // 辅助方法
    private AssetsTradePlan getPlanFromContext(org.springframework.statemachine.StateContext<TradePlanStatusEnum, TradePlanStatusEventEnum> context) {
        return (AssetsTradePlan) context.getExtendedState().getVariables().get("tradePlan");
    }

    private BigDecimal getCurrentPrice(String symbol) {
        // 模拟获取当前币价（实际集成API，如Binance）
        return new BigDecimal("180.0000"); // 示例：假设BTC价格
    }

    private boolean isPriceAtPosition(AssetsTradePlan plan) {
        // 假设指定位置：对于卖出，币价 > orderPrice * 1.05；买入 < orderPrice * 0.95
        BigDecimal current = getCurrentPrice(plan.getSymbol());
        plan.setCurrentPrice(current);
        if (plan.getTradeType() == 1) { // 买入
            return current.compareTo(plan.getOrderPrice().multiply(new BigDecimal("0.95"))) < 0;
        } else { // 卖出
            return current.compareTo(plan.getOrderPrice().multiply(new BigDecimal("1.05"))) > 0;
        }
    }

    private boolean planNeedsRedeem() {
        // 示例：从上下文中获取
        return false; // 实际从plan判断
    }
}